home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_ImportAdv / epsfreader.m < prev    next >
Text File  |  1992-12-19  |  14KB  |  555 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    epsfparser.m
  35.  *
  36.  *    ReadEpsf() is the procedure to invoke for parsing. It takes a pointer 
  37.  *    to a structure as an argument. This structure contains the pointer to
  38.  *    the data as well as the locations to place the results of the parsing.
  39.  *    This parser grabs the bounding box and the fonts. Other parsers
  40.  *    can add to this general structure to do more sophisticated parsing
  41.  *    such as page breakout and such.
  42.  *
  43.  *    Version:    2.0
  44.  *    Author:    Ken Fromm
  45.  *    History:
  46.  *            03-19-91        Added this comment.
  47.  */
  48.  
  49. #import "epsfstruct.h"
  50.  
  51. #import <appkit/nextstd.h>
  52. #import <objc/hashtable.h>
  53. #import <objc/List.h>
  54. #import <objc/Storage.h>
  55. #import <strings.h>
  56.  
  57. static int    processToField(EpsfStruct *epsf);
  58. static int  processToLineEnd(EpsfStruct *epsf);
  59.  
  60. static int  processBBox(EpsfStruct *epsf);
  61. static int  processIncludeFile(EpsfStruct *epsf);
  62. static int  processToEndDocument(EpsfStruct *epsf);
  63. static int  processDocumentResource(EpsfStruct *epsf);
  64. static int  processPageCount(EpsfStruct *epsf);
  65.  
  66. /*
  67. *    These static CommentHandle arrays are organized
  68. *    into different groups according to the level of the
  69. *    parsing. The general comments handle the top most
  70. *    level of parsing. The document comments handle 
  71. *    the parsing of an included document.
  72. *    
  73. *    This setup allows the same general flow to handle the 
  74. *    parsing of each group. When a comment is reached
  75. *    that indicates another level of  parsing should be
  76. *    performed, the tables for that level is passed to the 
  77. *    processToComment procedure.
  78. *
  79. *    Others group could be added (not necessarily for
  80. *    Epsf inclusion but for print management parsing). One
  81. *    example is a page comment group. This group would
  82. *    parse the page comments breaking out the location
  83. *    of the individual pages as well as fonts, colors, paper
  84. *    sizes, etc.
  85. *
  86. */
  87.  
  88. typedef struct {
  89.     char *comment;        int (*proc) (EpsfStruct *epsf);
  90. } CommentHandle;
  91.  
  92. /*****   General comments   *****/
  93. static CommentHandle generalComments [ ] =
  94. {
  95.     {"%%BoundingBox:",    processBBox},
  96.     {"%%BeginDocument",    processToEndDocument},
  97.     {"%%Document",        processDocumentResource},
  98.     {"%%Pages:",            processPageCount}
  99. };
  100.  
  101. /*****   Document comments   *****/
  102. static CommentHandle documentIncludeComments [ ] =
  103. {
  104.     {"%%BeginDocument",            processToEndDocument},
  105.     {"%%IncludeFile",                processIncludeFile}
  106. };
  107.  
  108. /*****   Document comments   *****/
  109. static CommentHandle documentEndComments [ ] =
  110. {
  111.     {"%%EndDocument",        processToLineEnd}
  112. };
  113.  
  114.  
  115. /*
  116. *    These static arrays are used to recognize the types of resources.
  117. *    For starters there are at present 5 types of resources - fonts, files,
  118. *    procsets, patterns and forms. Within each type, there are 3 states -
  119. *    present, needed and supplied. The present state is the union of the
  120. *    needed and supplied. The needed means the resource is not included
  121. *    with the document. The supplied means the resource is included with
  122. *    the document.
  123. */
  124.  
  125. typedef struct {
  126.     char *comment;        int  key;
  127. } ResourceHandle;
  128.  
  129. /*****   Resource comments   *****/
  130. static ResourceHandle resourceStates [ ] =
  131. {
  132.     {"Needed",                RES_NEEDED},
  133.     {"Supplied",                RES_SUPPLIED}
  134. };
  135.  
  136. static ResourceHandle resourceTypeMain [ ] =
  137. {
  138.     {"Fonts",                    RES_FONTS},
  139.     {"Files",                    RES_FILES},
  140.     {"ProcSets",                RES_PROCSETS},
  141.     {"Patterns",                RES_PATTERNS},
  142.     {"Forms",                    RES_FORMS},    
  143.     {"Resources",                RES_RESOURCES},
  144. };
  145.  
  146. static ResourceHandle resourceTypeSub [ ] =
  147. {
  148.     {"fonts",                    RES_FONTS},
  149.     {"files",                    RES_FILES},
  150.     {"procsets",                RES_PROCSETS},
  151.     {"patterns",                RES_PATTERNS},
  152.     {"forms",                    RES_FORMS}
  153. };
  154.  
  155. /*
  156. *    This is the workhorse of the parser. It takes a general structure
  157. *    and some pointers to CommentHandle arrays and processes
  158. *    the data until the one of the comments in the endTable has
  159. *    been reached or the data runs out.  Any matches to the 
  160. *    processTable comments processes the comment without
  161. *    returning. (Any match to the endTable returns after processing.)
  162. *
  163. *    If endLength is 0 then we will only process until the next line that
  164. *    is not a comment.
  165. */
  166. static int processToComment(EpsfStruct *epsf, CommentHandle endTable[ ], int endLength,
  167.         CommentHandle processTable[ ], int processLength)
  168. {
  169.     int        i, j;
  170.  
  171.     while (epsf->data < epsf->enddata)
  172.     {
  173.         if (strncmp(epsf->data, "%", 1) == 0)
  174.         {
  175.             for (j = 0; j < endLength; j++)
  176.             {
  177.                 if (strncmp(epsf->data, endTable[j].comment,
  178.                     strlen(endTable[j].comment)) == 0)
  179.                 {
  180.                     return endTable[j].proc(epsf);
  181.                 }
  182.             }
  183.  
  184.             for (i = 0; i < processLength; i++)
  185.             {
  186.                 if (strncmp(epsf->data, processTable[i].comment,
  187.                     strlen(processTable[i].comment)) == 0)
  188.                 {
  189.                     processTable[i].proc(epsf);
  190.                     break;
  191.                 }
  192.             }
  193.  
  194.             if (i == processLength)
  195.                 processToLineEnd(epsf);        
  196.         }
  197.         else
  198.         {
  199.              /* If endLength == 0 then process until the next non-comment. */
  200.              if (endLength == 0)
  201.                 return EPSF_OK;
  202.             else
  203.                 processToLineEnd(epsf);
  204.         }
  205.     }
  206.  
  207.     return EPSF_OK;
  208. }
  209.  
  210. static int CheckEpsf(EpsfStruct *epsf)
  211. {    
  212.     int        rc = EPSF_INVALIDPS;
  213.  
  214.     if (strncmp(epsf->data, "%!PS-Adobe-", 11) == 0)
  215.     {
  216.         processToField(epsf);
  217.         if (strncmp(epsf->data, "EPSF-", 5) == 0)
  218.         {
  219.             processToLineEnd(epsf);
  220.             rc = EPSF_OK;
  221.         }
  222.     }
  223.     
  224.     return rc;
  225. }
  226.  
  227. void  CheckEpsfBinaryHeader(char **data, int *len)
  228. {
  229.     EpsfBinaryHeader        *header;
  230.  
  231.     char        *newdata;
  232.  
  233.     int        newlen;
  234.     
  235.     /*
  236.     *    If a binary header file is encountered then just skip
  237.     *    to the PostScript section of the file. Update the
  238.     *    data and len arguments to reflect this change.
  239.     */
  240.     header = (EpsfBinaryHeader *) *data;
  241.     if (header->idbytes == EPSF_BINARYID)
  242.     {
  243.         newdata = *data + header->ps_start;
  244.         newlen = header->ps_length;
  245.  
  246.         if (newdata >= *data && newdata + newlen <= *data + *len)
  247.         {
  248.             *data = newdata;
  249.             *len = newlen;
  250.         }
  251.     }
  252. }
  253.  
  254. /*
  255. *    This is the routine invoked for parsing. It validates the file
  256. *    as a proper EPSF file (by checking for the %!PS-Adobe or
  257. *    for the binary header id) and then parses the file.
  258. */
  259. int  ReadEpsf(EpsfStruct *epsf)
  260. {
  261.     int        rc = EPSF_OK;
  262.  
  263.     if (epsf && epsf->filedata && *epsf->filedata)
  264.     {
  265.         CheckEpsfBinaryHeader(&epsf->filedata, &epsf->filelen);
  266.         epsf->data = epsf->filedata;
  267.         epsf->enddata = epsf->filedata + epsf->filelen;
  268.  
  269.         if (epsf->data < epsf->enddata && !CheckEpsf(epsf))
  270.         {
  271.             bzero(epsf->bbox, sizeof(epsf->bbox));
  272.             bzero(&epsf->resources, sizeof(epsf->resources));
  273.             bzero(&epsf->inclusions, sizeof(epsf->inclusions));
  274.  
  275.             while (epsf->data < epsf->enddata && !rc)
  276.             {
  277.                 rc = processToComment(epsf,
  278.                     generalComments, sizeof(generalComments)/sizeof(CommentHandle),
  279.                     NULL, 0); 
  280.             }
  281.  
  282.             /* Check for a valid bounding box. */
  283.             if (!rc && epsf->bbox[0] == 0 && epsf->bbox[1] == 0 &&
  284.                 epsf->bbox[2] == 0 && epsf->bbox[3] == 0)
  285.                 rc = EPSF_INVALIDBBOX;
  286.         }
  287.         else
  288.             rc =  EPSF_INVALIDPS;
  289.     }
  290.     else
  291.         rc =  EPSF_INVALIDPS;
  292.  
  293.     return rc;
  294. }
  295.  
  296. static int processToNonSpace(EpsfStruct *epsf)
  297. {
  298.     while (epsf->data < epsf->enddata && *epsf->data == ' ')
  299.         epsf->data++;
  300.     
  301.     return EPSF_OK;
  302. }
  303.  
  304. static int processToField(EpsfStruct *epsf)
  305. {
  306.  
  307.     while (epsf->data < epsf->enddata && *epsf->data != ':' && *epsf->data != ' ')
  308.         epsf->data++;
  309.     if (epsf->data < epsf->enddata && *epsf->data == ':')
  310.         epsf->data++;
  311.     processToNonSpace(epsf);
  312.     
  313.     return EPSF_OK;
  314. }
  315.  
  316. static int processToLineEnd(EpsfStruct  *epsf)
  317. {
  318.     while (epsf->data < epsf->enddata && *epsf->data != '\n')
  319.          epsf->data++;
  320.     if (epsf->data < epsf->enddata)
  321.         epsf->data++;
  322.     
  323.     return EPSF_OK;
  324. }
  325.  
  326. static int processBBox(EpsfStruct *epsf)
  327. {
  328.  
  329.     int        rc = EPSF_OK;
  330.     
  331.     processToField(epsf);
  332.     if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
  333.         if ((sscanf(epsf->data, "%f %f %f %f", &epsf->bbox[0], &epsf->bbox[1],
  334.             &epsf->bbox[2], &epsf->bbox[3]) != 4) ||
  335.             epsf->bbox[2] <= epsf->bbox[0] || epsf->bbox[3] <= epsf->bbox[1])
  336.             rc = EPSF_INVALIDBBOX;
  337.     
  338.     processToLineEnd(epsf);
  339.     
  340.     return rc;
  341. }
  342.  
  343. static int processIncludeFile(EpsfStruct *epsf)
  344. {
  345.     int            rc = EPSF_OK;
  346.  
  347.     char            name[EPSF_MAXLINE];
  348.  
  349.     Inclusion        inclusion;
  350.  
  351.     bzero(&inclusion, sizeof(inclusion));
  352.  
  353.     inclusion.offset = epsf->data - epsf->filedata;
  354.     processToField(epsf);
  355.     if (epsf->data < epsf->enddata)
  356.      {
  357.         if (sscanf(epsf->data, "%s", name))
  358.             inclusion.filename = NXUniqueString(name);
  359.  
  360.         processToLineEnd(epsf);
  361.         inclusion.len = (epsf->data - epsf->filedata) - inclusion.offset;
  362.  
  363.         if (inclusion.filename)
  364.         {    
  365.             if (!epsf->inclusions)
  366.                 epsf->inclusions= [Storage  newCount:0 elementSize:sizeof(Inclusion)                      description:InclusionDescription];
  367.             
  368.             [epsf->inclusions  addElement:&inclusion];
  369.         }
  370.     }
  371.     else
  372.         rc = EPSF_INVALIDDOCUMENT;
  373.  
  374.     return rc;
  375. }
  376.  
  377. static int processToEndDocument(EpsfStruct *epsf)
  378. {
  379.     processToLineEnd(epsf);
  380.     processToComment(epsf,
  381.         documentEndComments,
  382.             sizeof(documentEndComments)/sizeof(CommentHandle),
  383.         documentIncludeComments,
  384.             sizeof(documentIncludeComments)/sizeof(CommentHandle));
  385.  
  386.     if (epsf->data >= epsf->enddata)
  387.         return EPSF_INVALIDDOCUMENT;
  388.     else
  389.         return EPSF_OK;
  390. }
  391.  
  392. /* Checks the page count. If greater than 1, an error is returned. */
  393. /* Eps files should be single page documents only. */
  394. static int processPageCount(EpsfStruct *epsf)
  395. {
  396.     int        rc = EPSF_OK;
  397.  
  398.     int        pagetotal = 0;
  399.  
  400.     processToField(epsf);
  401.     if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
  402.         if (sscanf(epsf->data, "%d", &pagetotal))
  403.             if (pagetotal > 1)
  404.                 rc = EPSF_INVALIDPAGECOUNT;
  405.     
  406.     processToLineEnd(epsf);
  407.     
  408.     return rc;
  409. }
  410.  
  411. static int checkResource(EpsfStruct *epsf, ResourceHandle table[ ], int length)
  412. {
  413.     int        i;
  414.  
  415.     for (i = 0; i < length; i++)
  416.     {
  417.         if (epsf->data < epsf->enddata &&
  418.             strncmp(epsf->data, table[i].comment, strlen(table[i].comment)) == 0)
  419.         {
  420.             epsf->data += strlen(table[i].comment);
  421.             return table[i].key;
  422.         }
  423.     }
  424.  
  425.     return -1;
  426. }    
  427.  
  428. static int processResourceLine(EpsfStruct *epsf, int type, int state)
  429.  {
  430.      int            i;
  431.  
  432.     char            name[EPSF_MAXLINE], temp[40];
  433.  
  434.     if (!epsf->resources[type].states[state])
  435.         epsf->resources[type].states[state] = [List  new];
  436.  
  437.     processToNonSpace(epsf);
  438.     while (epsf->data < epsf->enddata && *epsf->data != '\n')
  439.      {
  440.         sscanf(epsf->data, "%s", name);
  441.         epsf->data += strlen(name);
  442.         processToNonSpace(epsf);
  443.          if (type == RES_PROCSETS)
  444.         {
  445.             for (i = 0; i < 2 && epsf->data < epsf->enddata && *epsf->data != '\n'; i++)
  446.             {
  447.                 if (sscanf(epsf->data, "%s", temp))
  448.                 {
  449.                     strcat(name, " ");
  450.                     strcat(name, temp);
  451.                     epsf->data += strlen(temp);
  452.                     processToNonSpace(epsf);
  453.                 }
  454.             }
  455.         }
  456.         [epsf->resources[type].states[state]
  457.                 addObjectIfAbsent:(id) NXUniqueString(name)];
  458.     }
  459.  
  460.     return EPSF_OK;
  461. }
  462.  
  463. static int processResources(EpsfStruct *epsf, int  xtype, int state)
  464. {
  465.     int        done = FALSE, type;
  466.  
  467.     type = xtype;
  468.     processToField(epsf);
  469.     if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
  470.     {
  471.         while (epsf->data < epsf->enddata && !done )
  472.         {
  473.             processToNonSpace(epsf);
  474.              if (*epsf->data == '\n')
  475.              {
  476.                  epsf->data++;
  477.                 if (epsf->data < epsf->enddata && strncmp(epsf->data, "%%+", 3) == 0)
  478.                     epsf->data += 3;
  479.                 else
  480.                     done = TRUE;
  481.             }
  482.             else
  483.             {
  484.                 if (xtype == RES_RESOURCES)
  485.                     type = checkResource(epsf, resourceTypeSub,
  486.                             sizeof(resourceTypeSub)/sizeof(ResourceHandle));
  487.  
  488.                 if (type >= RES_FONTS && type <= RES_FORMS)
  489.                     processResourceLine(epsf, type, state);
  490.                 else
  491.                     while (epsf->data < epsf->enddata && *epsf->data != '\n')
  492.                         epsf->data++;
  493.             }
  494.         }
  495.     }
  496.     else
  497.         processToLineEnd(epsf);
  498.  
  499.     return EPSF_OK;    
  500. }
  501.  
  502. static int processDocumentResource(EpsfStruct *epsf)
  503. {
  504.     int            state, type;
  505.  
  506.     epsf->data += 10;
  507.     if (epsf->data < epsf->enddata)
  508.     {
  509.         state = checkResource(epsf, resourceStates,
  510.                     sizeof(resourceStates)/sizeof(ResourceHandle));
  511.         state = MAX(RES_PRESENT, state);
  512.         type = checkResource(epsf, resourceTypeMain,
  513.                     sizeof(resourceTypeMain)/sizeof(ResourceHandle));
  514.         if (type >= 0)
  515.             processResources(epsf, type, state);
  516.     }
  517.  
  518.     return EPSF_OK;
  519. }
  520.  
  521. static char *getResource(int  key, ResourceHandle table[ ], int length)
  522. {
  523.     int        i;
  524.  
  525.     for (i = 0; i < length; i++)
  526.         if (table[i].key == key)
  527.             return table[i].comment;
  528.  
  529.     return NULL;
  530. }    
  531.  
  532. void GetDocumentComment(char *comment, int type, int state)
  533. {
  534.     char        *subOne, *subTwo;
  535.  
  536.     strcpy(comment, "%%%%Document");
  537.     subOne = getResource(state, resourceStates,
  538.                 sizeof(resourceStates)/sizeof(ResourceHandle));
  539.     if (subOne)
  540.         strcat(comment, subOne);
  541.     subTwo = getResource(type, resourceTypeMain,
  542.                 sizeof(resourceTypeMain)/sizeof(ResourceHandle));
  543.     if (subTwo)
  544.         strcat(comment, subTwo);
  545.     strcat(comment, ": ");
  546. }
  547.  
  548. const char *GetTypeComment(int type)
  549. {
  550.     return getResource(type, resourceTypeMain,
  551.                 sizeof(resourceTypeMain)/sizeof(ResourceHandle));
  552. }
  553.  
  554.     
  555.